/* Copyright 2009 The Revere Group
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wisco.plarform.core.base.dao.hibernate;

import java.io.Serializable;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.wisco.plarform.core.ProjectException;
import com.wisco.plarform.dao.Page;
import com.wisco.plarform.tools.DataTools;

/**
 * 
 * @author sunnly
 *
 * @param <T>
 * @param <ID>
 */
@SuppressWarnings("unchecked")
public class GenericDAOImpl<T, ID extends Serializable> extends
		HibernateDaoSupport implements GenericDAO<T, ID> {

	
	@Override
	public List find(String hql) {
		return this.getHibernateTemplate().find(hql);
	}

	@Override
	public List find(String hql, Object... params) {
		return this.getHibernateTemplate().find(hql, params);
	}

	@Override
	public List findAll(Class entityClass) {
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("开始删除实体：" + entityClass.getName());
			}
			return getHibernateTemplate().find("from " + entityClass.getName());
		} catch (RuntimeException e) {
			logger.error("查找指定实体集合异常，实体：" + entityClass.getName(), e);
			throw e;
		}
	}

	@Override
	public List findByArray(String hql, Object[] param) {
		return this.getHibernateTemplate().find(hql, param);
	}

	@Override
	public Object insert(Object object) throws ProjectException {
		Serializable save = this.getHibernateTemplate().save(object);
		return save;
	}

	@Override
	public Object get(Class entityClass, Serializable id) {
		return this.getHibernateTemplate().get(entityClass, id);
	}

	@Override
	public Object load(Class entityClass, Serializable id) {
		return this.getHibernateTemplate().load(entityClass, id);
	}

	@Override
	public List executeProduction(final String hql,
			final List<Integer> outParamType, final Object... param) {
		List list = (List) this.getHibernateTemplate().execute(
				new HibernateCallback() {
					// @Override
					public List doInHibernate(Session session)
							throws HibernateException, SQLException {
						Map map = null;
						List list = null;

						Connection conn = session.connection();
						CallableStatement cstmt = conn.prepareCall(hql);
						for (int i = 0; i < param.length; i++) {
							cstmt.setObject(i + 1, param[i]);
						}
						if (outParamType != null) {
							for (int j = 0; j < outParamType.size(); j++) {
								cstmt.registerOutParameter(
										j + param.length + 1, outParamType
												.get(j));
							}
							if (outParamType.size() == 0) {
								cstmt.executeUpdate();
								map = null;
							} else {
								ResultSet rs = cstmt.executeQuery();
								ResultSetMetaData rsmd = rs.getMetaData();
								int numberOfColumns = rsmd.getColumnCount();
								while (rs.next()) {
									map = new HashMap(numberOfColumns);
									list = new ArrayList();
									for (int r = 1; r < numberOfColumns + 1; r++) {
										map.put(rsmd.getColumnName(r), rs
												.getObject(r));
									}
									list.add(map);
								}
							}
						} else {
							cstmt.executeUpdate();
						}

						return list;
					}
				});
		return list;
	}

	@Override
	public List getListForPage(final String hql, final int offset,
			final int length) {

		List list = getHibernateTemplate().executeFind(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {

				Query query = session.createQuery(hql);
				query.setFirstResult(offset);
				query.setMaxResults(length);
				List list = query.list();

				return list;
			}

		});

		return list;

	}

	@Override
	public List getListForPage(final Class entityClass,
			final Criterion[] criterions, final int offset, final int length) {

		List list = getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {

				Criteria criteria = session.createCriteria(entityClass);
				// 循环遍历添加约束条件
				for (int i = 0; i < criterions.length; i++) {
					criteria.add(criterions[i]);
				}
				criteria.setFirstResult(offset);
				criteria.setMaxResults(length);
				return criteria.list();
			}
		});

		return list;

	}

	@Override
	public Object findById(Class entityClass, Serializable id) {
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("开始查找ID为" + id + "的实体：" + entityClass.getName());
			}
			return getHibernateTemplate().get(entityClass, id);
		} catch (RuntimeException e) {
			logger.error("查找指定ID实体异常，ID：" + id, e);
			throw e;
		}
	}

	@Override
	public Object findUnique(final String hql, final Object... values) {
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("开始查询返回唯一结果的HQL语句," + hql);
			}
			return getHibernateTemplate().execute(new HibernateCallback() {
				public Object doInHibernate(Session s)
						throws HibernateException, SQLException {
					Query query = createQuery(s, hql, values);
					return query.uniqueResult();
				}
			});
		} catch (RuntimeException e) {
			logger.error("查询指定HQL异常，HQL：" + hql, e);
			throw e;
		}
	}

	@Override
	public int findInt(final String hql, final Object... values) {
		return DataTools.null2Int(findUnique(hql, values));
	}

	@Override
	public int findTotalCount(Class entityClass, final String where,
			final Object... values) {
		String hql = "select count(e) from " + entityClass.getName() + " as e "
				+ where;
		return findInt(hql, values);
	}

	@Override
	public int findTotalCount(Class entityClass) {
		return findTotalCount(entityClass, "");
	}

	@Override
	public List findByProperty(Class entityClass, String propertyName,
			Object value) {
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("开始查找指定属性：" + propertyName + "为" + value + "的实体"
						+ entityClass.getName());
			}
			String queryStr = "from " + entityClass.getName()
					+ " as model where model." + propertyName + "=?";
			return getHibernateTemplate().find(queryStr, value);
		} catch (RuntimeException e) {
			logger.error("查找指定条件实体集合异常，条件：" + propertyName, e);
			throw e;
		}
	}

	@Override
	public List findByExample(Object entity) {
		try {
			List results = getHibernateTemplate().findByExample(entity);
			return results;
		} catch (RuntimeException re) {
			logger.error("查找指定条件实体集合异常", re);
			throw re;
		}
	}

	@Override
	public Object merge(Object entity) {
		try {
			Object result = (Object) getHibernateTemplate().merge(entity);
			return result;
		} catch (RuntimeException re) {
			logger.error("merge异常", re);
			throw re;
		}
	}

	@Override
	public void attachClean(Object entity) {
		try {
			getHibernateTemplate().lock(entity, LockMode.NONE);
		} catch (RuntimeException re) {
			logger.error("实体解锁异常", re);
			throw re;
		}
	}

	@Override
	public Page findByPage(final Page page, final String hql,
			final Object... values) {
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("开始查找指定HQL分页数据," + hql);
			}
			return (Page) getHibernateTemplate().execute(
					new HibernateCallback() {
						public Object doInHibernate(Session s)
								throws HibernateException, SQLException {
							Query query = createQuery(s, hql, values);
							if (page.isFirstSetted()) {
								query.setFirstResult(page.getFirst());
							}
							if (page.isPageSizeSetted()) {
								query.setMaxResults(page.getPageSize());
							}
							page.setResult(query.list());
							if (logger.isDebugEnabled()) {
								logger.debug("查找指定HQL分页数据成功," + hql);
							}
							return page;
						}
					});
		} catch (RuntimeException e) {
			logger.error("分页查询异常，HQL：" + hql, e);
			throw e;
		}
	}

	@Override
	public boolean save(Object entity) {
		try {
			getHibernateTemplate().save(entity);
			if (logger.isDebugEnabled()) {
				logger.debug("保存实体类成功," + entity.getClass().getName());
			}
			return true;
		} catch (RuntimeException e) {
			logger.error("保存实体异常," + entity.getClass().getName(), e);
			throw e;
		}
	}
	

	@Override
	public void saveOrUpdate(Object entity) {
		try {
			getHibernateTemplate().saveOrUpdate(entity);
			if (logger.isDebugEnabled()) {
				logger.debug("更新或者保存实体成功," + entity.getClass().getName());
			}
		} catch (RuntimeException e) {
			logger.error("更新或保存实体异常", e);
			throw e;
		}
	}

	@Override
	public Query createQuery(Session session, String hql, Object... objects) {
		Query query = session.createQuery(hql);
		if (objects != null) {
			for (int i = 0; i < objects.length; i++) {
				query.setParameter(i, objects[i]);
			}
		}
		return query;
	}

	@Override
	public boolean delete(Object entity) {
		try {
			getHibernateTemplate().delete(entity);
			if (logger.isDebugEnabled()) {
				logger.debug("删除实体类成功," + entity.getClass().getName());
			}
			return true;
		} catch (RuntimeException e) {
			logger.error("删除实体异常", e);
			throw e;
		}
	}

}